﻿using System.Collections.Generic;
using System.Threading;
using System.Web.UI;
using System.Web.UI.WebControls;
using visinia.SmartEngine.Pages;

namespace visinia.SmartEngine.Modules
{
    public class WebModuleController
    {        
        #region MODES
        private static MODES _CURRENT_MODE;
        /// <summary>
        /// visinia webpage can run in two mode first one the normal one user mode
        /// is used for normal page rendering.
        /// the other mode designer mode is the mode used to set the webpage layout 
        /// to add modules on the page to delete the modules are to drag a module from
        /// one pane and drop to the other pane on the page. In this mode module properties
        /// can be changed.
        /// </summary>
        public enum MODES
        {
            /// <summary>
            /// The normal web page mode.
            /// </summary>
            USER = 0,
            /// <summary>
            /// The mode used for the web page designer, to add delete update modules, change module settings
            /// to drag drop module, to stake modules in the required order
            /// </summary>
            DESIGNER = 1,
        }

        /// <summary>
        /// The current mode of the webpage
        /// </summary>
        public static MODES CURRENT_MODE
        {
            get
            {
                return _CURRENT_MODE;
            }
            set
            {
                _CURRENT_MODE = value;
            }
        }

        #endregion

        public static bool LoadModules(int PageId, Page webpage, WebModuleController.MODES mode)
        {
            if (webpage == null)
                return false;
            PageInfo page = PageController.GetPage(PageId);
                if (page == null)
                    return false;
            if (mode == MODES.USER)
            {
                if (Thread.CurrentPrincipal.IsInRole("designer") || (Thread.CurrentPrincipal.IsInRole("admin")))
                    LoadAdminBarMini(webpage);                
                CURRENT_MODE = MODES.USER;
                WebModuleController.LoadModules(page.PageId, webpage);
                if (!string.IsNullOrEmpty(page.Title))
                    webpage.Title = page.Title;
                return true;
            }
            if (mode == MODES.DESIGNER)
            {
                if (!(Thread.CurrentPrincipal.IsInRole("designer") || (Thread.CurrentPrincipal.IsInRole("admin"))))
                    return false;                
                CURRENT_MODE = MODES.DESIGNER;
                WebModuleController.LoadDesignerModeModules(page.PageId, webpage);
                if (!string.IsNullOrEmpty(page.Title))
                    webpage.Title = page.Title + " - DESIGN MODE";
                return true;
            }
            return false;
        }

        /// <summary>
        /// Loads the specified page modules at there specific panes
        /// </summary>
        /// <param name="PageId">The page whose modules to load</param>
        /// <param name="webpage">The actual web page object</param>
        private static void LoadModules(int PageId, Page webpage)
        {
            // get all the modules of this page from the data store
            List<ModuleInfo> modules = ModuleController.GetModules(PageId);
            foreach (ModuleInfo module in modules)
            {
                if (!module.Visible)
                    continue;
                // find the pane this module will be added to
                ContentPlaceHolder pane = (ContentPlaceHolder)webpage.Master.FindControl(module.Pane);
                if (pane != null)
                {
                    try
                    {
                        // loads the specific module ascx file (UserControl)
                        WebModule webmodule = (WebModule)webpage.LoadControl(WebRoots.GetModulesRoot + module.ModuleUrl);
                        // required to pass so it can later use ModuleId to access its private settings etc.
                        webmodule.ModuleId = module.ModuleId;
                        // adds the module to the specific pane
                        pane.Controls.Add(webmodule);
                    }
                    catch
                    {// on error just keep going 
                        // I don't want to show an error to an end user because he has no use of it.
                        continue;
                    }
                }
            }
        }

        private static void LoadAdminBarMini(Page webPage)
        {
            Control adminbar = webPage.LoadControl(WebRoots.GetAdminRoot + "Controls/AdminBarMini.ascx");
            Control form = null;
            foreach (Control control in webPage.Master.Controls)
            {
                if (control.GetType().Name == "HtmlForm")
                {
                    form = control;
                    break;
                }
            }
            if (form != null)
                form.Controls.AddAt(0, adminbar);
        }

        /// <summary>
        /// Loads the specified page modules at there specific panes in the Designer Mode
        /// </summary>
        /// <param name="PageId">The page whose modules to load</param>
        /// <param name="Webpage">The actual web page object</param>
        private static void LoadDesignerModeModules(int PageId, Page Webpage)
        {
            int all_Pane_Modules = 0;// used for orphan modules
            foreach (Control c in Webpage.Master.Controls)
            {
                foreach (Control paneCPH in c.Controls)
                {
                    if (paneCPH is ContentPlaceHolder)
                    {
                        string pane = paneCPH.ID;
                        // in desigenr mode every pane has a div with class "column"
                        // these actually serve as the drag drop containers
                        // every div with "dragbox" class inside a div with "column" class will be draggable
                        // and in visinia every module in designer mode is rendered indise a
                        // div with class "dragbox"
                        // So every module will be draggable abd droppable                            
                        // also draws a border to make it easy to distinguish
                        LiteralControl lchead = new LiteralControl("<div class=\"column\" id=\"" + pane + "\" >");
                        paneCPH.Controls.Add(lchead);
                        string divstr = "<div class=\"pane-title\" >" + pane + "</div>";
                        LiteralControl divctrl = new LiteralControl(divstr);
                        paneCPH.Controls.Add(divctrl);
                        List<ModuleInfo> modules = ModuleController.GetModules(PageId, pane);
                        all_Pane_Modules += modules.Count;
                        foreach (ModuleInfo module in modules)
                        {
                            try
                            {
                                WebModule webmodule = (WebModule)Webpage.LoadControl(WebRoots.GetModulesRoot + module.ModuleUrl);
                                webmodule.ModuleId = module.ModuleId;
                                paneCPH.Controls.Add(webmodule);
                            }
                            catch
                            {// just keep going 
                                continue;
                            }
                        }
                        LiteralControl lcfooter = new LiteralControl("</div>");
                        paneCPH.Controls.Add(lcfooter);
                    }
                }

            }
            LoadAdminBar(PageId, Webpage, all_Pane_Modules);
        }

        private static void LoadAdminBar(int PageId, Page webpage, int all_Pane_Modules)
        {
            AdminBar adminbar = (AdminBar)webpage.LoadControl(WebRoots.GetAdminRoot + "Controls/AdminBar.ascx");
            adminbar.DataBindOrphanModules(LoadOrphanModules(PageId, webpage, all_Pane_Modules));
            Control form = null;
            foreach (Control control in webpage.Master.Controls)
            {
                if (control.GetType().Name == "HtmlForm")
                {
                    form = control;
                    break;
                }
            }
            if (form != null)
                form.Controls.AddAt(0, adminbar);
        }

        /// <summary>
        /// If a pane on the webpage theme is deleted or renamed and that pane 
        /// had a module inside it, that module is called orphan module, those modules will not be
        /// loaded in user mode
        /// but when in designer mode those all modules will be added to the orphan list
        /// </summary>        
        private static List<ModuleInfo> LoadOrphanModules(int PageId, Page webpage, int all_Pane_Modules)
        {
            List<ModuleInfo> orphanlist = new List<ModuleInfo>();
            List<ModuleInfo> modulescurrentpage = ModuleController.GetModules(PageId);
            if (all_Pane_Modules < modulescurrentpage.Count)
            {
                // a pane in theme is renamed or deleted which has modules in it
                foreach (ModuleInfo module in modulescurrentpage)
                {  //check the panes in the master file
                    if (webpage.Master.FindControl(module.Pane) == null)
                    {
                        orphanlist.Add(module);
                    }
                }
            }
            return orphanlist;
        }        
    }
}
